package com.radar.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.radar.common.DateConstants;
import com.radar.common.GisConstants;
import com.radar.exception.RadarDecodeError;
import com.radar.io.CinradRadar;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.meteoinfo.data.GridData;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import sun.misc.BASE64Encoder;
import ucar.nc2.dataset.NetcdfDataset;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Api(tags = "2.0 雷达接口")
@RestController
@RequestMapping("radr")
@Slf4j
public class RadarController {

    private String processPath;

    @Value("${ncPath:''}")
    public void setProcessPath(String processPath) {
        this.processPath = processPath;
    }


//    @ApiOperation("2.2.单点雷达数据")
//    @GetMapping("/point")
//    @ApiImplicitParams({
//            @ApiImplicitParam(name = "obsTime", value = "obsTime", defaultValue = "2021-03-04 23:59:00", example = "2021-03-04 23:59:00", paramType = "query", required = true, dataType = "String"),
//            @ApiImplicitParam(name = "index", value = "ref、vel的 index", defaultValue = "0", example = "0", paramType = "query", required = true, dataType = "int"),
//            @ApiImplicitParam(name = "lon", value = "lon", defaultValue = "0", example = "0", paramType = "query", required = true, dataType = "int"),
//            @ApiImplicitParam(name = "lat", value = "lat", defaultValue = "0", example = "0", paramType = "query", required = true, dataType = "int")
//    })
//    public ResultBody point(@ApiIgnore @RequestParam String obsTime, @RequestParam int index, @RequestParam double lon, @RequestParam double lat) {
//        CinradRadar cinradRadar = null;
//        try {
//            if (StringUtils.isBlank(obsTime)) {
//                return ResultBody.failed();
//            }
//            Date parse = DateUtil.parse(obsTime, DateConstants.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
//            String realPath = this.processPath + File.separator + DateUtil.format(parse, DateConstants.DATE_FORMAT_YYYYMMDD) + File.separator + DateUtil.format(parse, DateConstants.DATE_FORMAT_YYYYMMDDHHMM) + File.separator;
//            List<File> files = FileUtil.loopFiles(realPath, new RegexFileFilter("^Z_RADR_I_Z(\\d{4})_(\\d{14})_O_DOR_(.*?)_CAP_FMT.(BIN.BZ2|bin.bz2|bin)$"));
//            if (files == null || files.size() != 1) {
//                return ResultBody.failed();
//            }
//            cinradRadar = new CinradRadar();
//            // TODO 修改自定义站点
//            if (radarcode.equals("")) {
//                cinradRadar.parse(files.get(0).getAbsolutePath());
//            } else {
//                cinradRadar.parse(files.get(0).getAbsolutePath(), null, radarcode);
//            }
//            double ref = cinradRadar.radar.point(lon, lat, ProductType.REF, index);
//            double vel = cinradRadar.radar.point(lon, lat, ProductType.VEL, index);
//            double sw = cinradRadar.radar.point(lon, lat, ProductType.SW, index);
//            cinradRadar.radar.close();
//            return ResultBody.ok().put("ref", ref).put("vel", vel).put("sw", sw);
//        } catch (Exception e) {
//            log.error(ExceptionUtil.getSimpleMessage(e));
//        }
//        return ResultBody.failed();
//    }
//
//    @ApiOperation("2.2.单点雷达数据 数据类型获取")
//    @GetMapping("/pointType")
//    @ApiImplicitParams({
//            @ApiImplicitParam(name = "obsTime", value = "obsTime", defaultValue = "2021-03-04 23:59:00", example = "2021-03-04 23:59:00", paramType = "query", required = true, dataType = "String"),
//            @ApiImplicitParam(name = "lon", value = "lon", defaultValue = "0", example = "0", paramType = "query", required = true, dataType = "int"),
//            @ApiImplicitParam(name = "lat", value = "lat", defaultValue = "0", example = "0", paramType = "query", required = true, dataType = "int")
//    })
//    public ResultBody pointType(@ApiIgnore @RequestParam String obsTime, @RequestParam double lon, @RequestParam double lat) {
//        try {
//            if (StringUtils.isBlank(obsTime)) {
//                return ResultBody.failed();
//            }
//            Date parse = DateUtil.parse(obsTime, DateConstants.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
//            String realPath = this.processPath + File.separator + DateUtil.format(parse, DateConstants.DATE_FORMAT_YYYYMMDD) + File.separator + DateUtil.format(parse, DateConstants.DATE_FORMAT_YYYYMMDDHHMM) + File.separator;
//            List<File> files = FileUtil.loopFiles(realPath, new RegexFileFilter("^Z_RADR_I_Z(\\d{4})_(\\d{14})_O_DOR_(.*?).nc$"));
//            files.addAll(FileUtil.loopFiles(realPath, new RegexFileFilter("^LD(\\d{14})(\\d{3}).(VT382|VT346).nc$")));
//            double crvalue = GisConstants.UNDEF;
//            if (files != null && files.size() == 1) {
//                NetcdfDataset netcdfDataset = NetcdfDataset.openDataset(files.get(0).getAbsolutePath());
//                GridData cr = new GridData();
//                cr.xArray = (double[]) netcdfDataset.findVariable("Longitude_REF").read().copyTo1DJavaArray();
//                cr.yArray = (double[]) netcdfDataset.findVariable("Latitude_REF").read().copyTo1DJavaArray();
//                cr.data = (double[][]) netcdfDataset.findVariable("CR").read().copyToNDJavaArray();
//                cr.missingValue = Double.NaN;
//                cr.projInfo = GisConstants.lonlat;
//                crvalue = cr.toStation(lon, lat);
//                netcdfDataset.close();
//            }
//            return ResultBody.ok()
//                    .put("CR", crvalue);
//        } catch (Exception e) {
//            log.error(ExceptionUtil.getSimpleMessage(e));
//        }
//        return ResultBody.failed();
//    }
//
//    @ApiOperation("2.2.单点雷达数据 数据类型获取")
//    @GetMapping("/cappiData")
//    @ApiImplicitParams({
//            @ApiImplicitParam(name = "obsTime", value = "obsTime", defaultValue = "2021-03-04 23:59:00", example = "2021-03-04 23:59:00", paramType = "query", required = true, dataType = "String"),
//            @ApiImplicitParam(name = "level", value = "cappi level", defaultValue = "0", example = "0", paramType = "query", required = true, dataType = "double"),
//            @ApiImplicitParam(name = "lon", value = "lon", defaultValue = "0", example = "0", paramType = "query", required = true, dataType = "int"),
//            @ApiImplicitParam(name = "lat", value = "lat", defaultValue = "0", example = "0", paramType = "query", required = true, dataType = "int")
//    })
//    public ResultBody cappiData(@ApiIgnore @RequestParam String obsTime, @RequestParam double level) {
//        try {
//            if (StringUtils.isBlank(obsTime)) {
//                return ResultBody.failed();
//            }
//            Date parse = DateUtil.parse(obsTime, DateConstants.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
//            String realPath = this.processPath + File.separator + DateUtil.format(parse, DateConstants.DATE_FORMAT_YYYYMMDD) + File.separator + DateUtil.format(parse, DateConstants.DATE_FORMAT_YYYYMMDDHHMM) + File.separator;
//            List<File> files = FileUtil.loopFiles(realPath, new RegexFileFilter("^Z_RADR_I_Z(\\d{4})_(\\d{14})_O_DOR_(.*?).nc$"));
//            files.addAll(FileUtil.loopFiles(realPath, new RegexFileFilter("^LD(\\d{14})(\\d{3}).(VT382|VT346).nc$")));
//            if (files != null && files.size() == 1) {
//                NetcdfDataset netcdfDataset = NetcdfDataset.openDataset(files.get(0).getAbsolutePath());
//                GridData cr = new GridData();
//                cr.xArray = (double[]) netcdfDataset.findVariable("Longitude_REF").read().copyTo1DJavaArray();
//                cr.yArray = (double[]) netcdfDataset.findVariable("Latitude_REF").read().copyTo1DJavaArray();
//                Extent extent = cr.getExtent();
//                netcdfDataset.close();
//                if (cr != null) {
//                    files = FileUtil.loopFiles(realPath, new RegexFileFilter("^surface.dat.zip$"));
//                    if (files != null && files.size() == 1) {
//                        // 获取cappi 数据
//                        double[] alt = new double[]{1000, 1500, 2000, 2500, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000};
//                        int zindex = Arrays.binarySearch(alt, level);
//                        String file = files.get(0).getParentFile().getAbsolutePath() + File.separator + "surface.dat" + File.separator + "surface.dat";
//                        if (!FileUtil.exist(file)) {
//                            ZipUtil.unzip(files.get(0));
//                        }
//                        if (zindex >= 0 && zindex < alt.length) {
//                            byte[] bytes = FileUtil.readBytes(file);
//                            GridData gridData = new GridData();
//                            gridData.xArray = new double[500];
//                            gridData.yArray = new double[500];
//                            IntStream.range(0, 500).forEach(i -> gridData.xArray[i] = extent.minX + extent.getWidth() / 500.0 * i);
//                            IntStream.range(0, 500).forEach(i -> gridData.yArray[i] = extent.minY + extent.getHeight() / 500.0 * i);
//                            gridData.data = new double[500][500];
//                            gridData.missingValue = Double.NaN;
//                            gridData.projInfo = GisConstants.lonlat;
//                            int index = 500 * 500 * zindex;
//                            for (int i = 0; i < 500; i++) {
//                                for (int j = 0; j < 500; j++) {
//                                    gridData.data[i][j] = bytes[index];
//                                    index++;
//                                }
//                            }
//                            return ResultBody.ok()
//                                    .put("data", gridData.data)
//                                    .put("xarray", gridData.xArray)
//                                    .put("yarray", gridData.yArray)
//                                    .put("extent", gridData.getExtent());
//                        }
//                    }
//                }
//            }
//        } catch (Exception e) {
//            log.error(ExceptionUtil.getSimpleMessage(e));
//        }
//        return ResultBody.failed();
//    }
//
//    @ApiOperation("2.3.剖面")
//    @GetMapping("/vcs")
//    @ApiImplicitParams({
//            @ApiImplicitParam(name = "obsTime", value = "obsTime", defaultValue = "/Users/xx/data/micaps/SINGLERADAR/ARCHIVES/PRE_QC/Z9836/Z_RADR_I_Z9836_20190730022600_O_DOR_CA_CAP.bin.bz2", example = "/Users/xx/data/micaps/SINGLERADAR/ARCHIVES/PRE_QC/Z9836/Z_RADR_I_Z9836_20190730022600_O_DOR_CA_CAP.bin.bz2", paramType = "query", required = true, dataType = "String"),
//            @ApiImplicitParam(name = "type", value = "产品类别(REF,VEL,CR,ET,VIL)", defaultValue = "REF", example = "REF", paramType = "query", required = true, dataType = "String"),
//            @ApiImplicitParam(name = "points", value = "点集合", defaultValue = "points", example = "110-27,111-27", paramType = "query", required = true, dataType = "String")
//    })
//    public ResultBody vcs(@ApiIgnore @RequestParam String obsTime, @RequestParam String points, @RequestParam String type) {
//        CinradRadar cinradRadar = null;
//        try {
//            if (StringUtils.isBlank(obsTime)) {
//                return ResultBody.failed();
//            }
//            Date parse = DateUtil.parse(obsTime, DateConstants.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
//            String realPath = this.processPath + File.separator + DateUtil.format(parse, DateConstants.DATE_FORMAT_YYYYMMDD) + File.separator + DateUtil.format(parse, DateConstants.DATE_FORMAT_YYYYMMDDHHMM) + File.separator;
//            List<File> files = FileUtil.loopFiles(realPath, new RegexFileFilter("^Z_RADR_I_Z(\\d{4})_(\\d{14})_O_DOR_(.*?)_CAP_FMT.(BIN.BZ2|bin.bz2|bin)$"));
//            files.addAll(FileUtil.loopFiles(realPath, new RegexFileFilter("^LD(\\d{14})(\\d{3}).(VT382|VT346)$")));
//            if (files == null || files.size() != 1) {
//                return ResultBody.failed();
//            }
//            cinradRadar = new CinradRadar();
//            // TODO 修改自定义站点
//            if (radarcode.equals("")) {
//                cinradRadar.parse(files.get(0).getAbsolutePath());
//            } else if (files.get(0).getName().contains("382")) {
//                cinradRadar.parse(files.get(0).getAbsolutePath(), CinradType.RADAR_382);
//                ((Radar382)cinradRadar.radar).lon = 116.7;
//                ((Radar382)cinradRadar.radar).lat = 20.9;
//            } else {
//                cinradRadar.parse(files.get(0).getAbsolutePath(), null, radarcode);
//            }
//
////            cinradRadar.radar.setProjectStep(0.02);
//            List<PointD> list = new ArrayList<>();
//            Arrays.asList(points.split(";")).forEach(i -> {
//                list.add(new PointD(Double.parseDouble(i.split(":")[0]), Double.parseDouble(i.split(":")[1])));
//            });
//            VCSMap vcsMap = new VCSMap(cinradRadar.radar);
//            VCSMap.VCSInfo vcsInfo = vcsMap.buildRasterInfo(ProductType.valueOf(type))
//                    .altNum(100)
//                    .pointNum(500)
//                    .maxAlt(22);
//            BufferedImage bufferedImage = vcsMap.simpleVCS(vcsInfo, list);
//            cinradRadar.radar.close();
//            return ResultBody.ok().data(imageToBase64(bufferedImage));
//        } catch (Exception e) {
//            log.error(ExceptionUtil.getSimpleMessage(e));
//            if (cinradRadar.radar != null) {
//                cinradRadar.radar.close();
//            }
//        }
//        return ResultBody.failed();
//    }

    @ApiOperation(value = "时间轴", httpMethod = "GET", notes = "listTimeLine")
    @GetMapping("/listTimeLine")
    public HashMap<String, Object> listTimeLine(String yyyyMMdd) {
        try {
            if (!yyyyMMdd.isEmpty()) {
                // 时间参数格式判断
                DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd");
                fmt.parseLocalDateTime(yyyyMMdd).toDate();
            }
        } catch (Exception e) {
            return new HashMap<>();
        }
        HashMap<String, Object> timeLine = getTimeLine(yyyyMMdd);
        return timeLine;
    }

    public HashMap<String, Object> getTimeLine(String yyyyMMdd) {
        try {
//            File dir;
//            if (yyyyMMdd == null || yyyyMMdd.isEmpty()) {
//                dir = Arrays.stream(FileUtil.ls(processPath))
//                        .filter(i -> i.getName().length() == 8).min(Comparator.comparing(i -> -Long.parseLong(i.getName()))).orElse(null);
//            } else {
//                dir = new File(processPath + File.separator + DateUtil.format(DateUtil.parse(yyyyMMdd, "yyyy-MM-dd"), "yyyyMMdd"));
//            }
//            if (dir == null) {
//                return null;
//            }


            List<DateTime> collect = Arrays.stream(FileUtil.ls(processPath))
                    .filter(i -> i.getName().length() == 17).map(file -> DateUtil.parse(file.getName().substring(0, 17), DateConstants.DATE_TIME_FORMAT_YYYYMMDDHHMISSSSS)).sorted().collect(Collectors.toList());
            List<Map<String, String>> list = new ArrayList<>();
            if (yyyyMMdd == null || yyyyMMdd.isEmpty()) {
                for (Date date : collect) {
                    Map map = new HashMap();
                    map.put("timestamp", DateUtil.format(date, "yyyy-MM-dd HH:mm:ss"));
                    map.put("timeColor", "rgba(55,54,55,1)");
                    map.put("showDay", false);
                    map.put("showHour", false);
                    int minute = DateUtil.minute(date);
                    if (Math.abs(minute - 30) < 3) {//|| Math.abs(minute - 30) < 3 || Math.abs(minute - 0) < 3
                        map.put("timeStyleHeight", "15px");
                        map.put("showDay", true);
                        map.put("showHour", true);
                    } else {
                        map.put("timeStyleHeight", "5px");
                    }
                    map.put("disabled", false);
                    // 判断下 nc 文件是否存在
                    list.add(map);
                }
            }else {
                long apiTime = DateUtil.parse(yyyyMMdd, "yyyy-MM-dd").getTime();
                for (Date date : collect) {
                    long fileTime = date.getTime();
                    if (fileTime<apiTime) {
                        Map map = new HashMap();
                        map.put("timestamp", DateUtil.format(date, "yyyy-MM-dd HH:mm:ss"));
                        map.put("timeColor", "rgba(55,54,55,1)");
                        map.put("showDay", false);
                        map.put("showHour", false);
                        int minute = DateUtil.minute(date);
                        if (Math.abs(minute - 30) < 3) {//|| Math.abs(minute - 30) < 3 || Math.abs(minute - 0) < 3
                            map.put("timeStyleHeight", "15px");
                            map.put("showDay", true);
                            map.put("showHour", true);
                        } else {
                            map.put("timeStyleHeight", "5px");
                        }
                        map.put("disabled", false);
                        // 判断下 nc 文件是否存在
                        list.add(map);
                    }
                }
            }
            HashMap timeLineMap = new HashMap();
            timeLineMap.put("initializationPosition", list.size() - 1);
            timeLineMap.put("data", list);
            return timeLineMap;
        } catch (Exception e) {
            return null;
        }
    }

    public String imageToBase64(BufferedImage br) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流
        ImageIO.write(br, "png", baos);//写入流中
        byte[] bytes = baos.toByteArray();//转换成字节
        BASE64Encoder encoder = new BASE64Encoder();
        String pngBase64 = encoder.encodeBuffer(bytes).trim();//转换成base64串
        pngBase64 = pngBase64.replaceAll("\n", "").replaceAll("\r", "");//删除 \r\n
        return pngBase64;
    }

    public static void main(String[] args) throws RadarDecodeError, IOException {
        String file = "Z:\\cctv-out\\SingleRadar\\20210716\\202107160320\\Z_RADR_I_Z9090_20210716032018_O_DOR_SB_CAP_FMT.bin.nc";
        NetcdfDataset netcdfDataset = NetcdfDataset.openDataset(file);
        GridData gridData = new GridData();
        gridData.xArray = (double[]) netcdfDataset.findVariable("Longitude_REF").read().copyTo1DJavaArray();
        gridData.yArray = (double[]) netcdfDataset.findVariable("Latitude_REF").read().copyTo1DJavaArray();
        gridData.data = (double[][]) netcdfDataset.findVariable("CR").read().copyToNDJavaArray();
        gridData.missingValue = GisConstants.UNDEF;
        gridData.projInfo = GisConstants.lonlat;
        System.out.println();
        CinradRadar cinradRadar = new CinradRadar();
        cinradRadar.parse(file);
        cinradRadar.radar.globalAttr.forEach(System.out::println);
        System.out.println(cinradRadar.radar.globalAttr);
    }
}
